package encoder

import (
	"encoding/base64"
	"encoding/hex"
)

type Encoder interface {
	Encode([]byte, []byte)
	EncodeToString([]byte) string
	Decode([]byte) ([]byte, error)
	DecodeString(string) ([]byte, error)
}

type (
	base64Encoder struct{}
	hexEncoder    struct{}
	byteEncoder   struct{}
)

var (
	_ Encoder = (*base64Encoder)(nil)
	_ Encoder = (*hexEncoder)(nil)
	_ Encoder = (*byteEncoder)(nil)

	Base64Encoder base64Encoder
	HexEncoder    hexEncoder
)

func (e *base64Encoder) Encode(dst, src []byte) {
	base64.StdEncoding.Encode(dst, src)
}

func (e *base64Encoder) EncodeToString(src []byte) string {
	return base64.StdEncoding.EncodeToString(src)
}

func (e *base64Encoder) Decode(src []byte) ([]byte, error) {
	dst := make([]byte, base64.StdEncoding.DecodedLen(len(src)))

	n, err := base64.StdEncoding.Decode(dst, src)
	if err != nil {
		return nil, err
	}

	return dst[:n], nil
}

func (e *base64Encoder) DecodeString(s string) ([]byte, error) {
	return base64.StdEncoding.DecodeString(s)
}

func (e *hexEncoder) Encode(dst, src []byte) {
	hex.Encode(dst, src)
}

func (e *hexEncoder) EncodeToString(src []byte) string {
	return hex.EncodeToString(src)
}

func (e *hexEncoder) Decode(src []byte) ([]byte, error) {
	dst := make([]byte, hex.DecodedLen(len(src)))

	n, err := hex.Decode(dst, src)
	if err != nil {
		return nil, err
	}

	return dst[:n], nil
}

func (e *hexEncoder) DecodeString(s string) ([]byte, error) {
	return hex.DecodeString(s)
}

func (e *byteEncoder) Encode(dst, src []byte) {
	copy(dst, src)
}

func (e *byteEncoder) EncodeToString(src []byte) string {
	return string(src)
}

func (e *byteEncoder) Decode(src []byte) ([]byte, error) {
	return src, nil
}

func (e *byteEncoder) DecodeString(s string) ([]byte, error) {
	return []byte(s), nil
}
